
package com.hjzd.ai.smartpractice.entity.DTO.chat;

import com.google.gson.*;
import com.hjzd.ai.smartpractice.service.RedisService;
import com.hjzd.ai.smartpractice.websocket.AliTtsClient;
import com.hjzd.ai.smartpractice.websocket.SessionManager;
import com.hjzd.ai.smartpractice.websocket.StepfunTTSClient;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

import static com.hjzd.ai.smartpractice.constant.ServiceConstant.*;
import static com.hjzd.ai.smartpractice.websocket.SessionManager.SENTENCE_CACHE;

public class ChatResponseThread extends Thread {

    private static final Logger logger = LoggerFactory.getLogger(ChatResponseThread.class);
    private static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
            .setLongSerializationPolicy(LongSerializationPolicy.STRING).disableHtmlEscaping().create();
    HttpClient client;
    WebSocketSession session;
    RedisService redisService;
    ChatCompletionRequest chatCompletionRequest;
    boolean running = true;
    boolean interruptTTS = true;
    String ttsUrl;
    int sentWordCount = 0;
    public String saveVoicePath;

    // 是否使用 Stepfun TTS
    private String ttsType;
    private StepfunTTSClient ttsClient;
    private AliTtsClient aliTtsClient;

    private static final String TTS_APP_ID = "1393667404";
    private static final String TTS_TOKEN = "9eGvcslDRowNgVESTSxg-DUJkEezgVGs";
    private static final String TTS_CLUSTER = "volcano_tts";
    private static final String DEFAULT_USER_UID = "388808087185088";
    private static final String VOICE_TYPE = "zh_female_shuangkuaisisi_moon_bigtts";

    public ChatResponseThread(WebSocketSession session, String ttsUrl, String saveVoicePath, String ttsType, StepfunTTSClient ttsClient, AliTtsClient aliTtsClient) {
        this.session = session;
        this.client = HttpClient.newHttpClient();
        this.ttsUrl = ttsUrl;
        this.saveVoicePath = saveVoicePath;
        this.ttsType = ttsType;
        this.ttsClient = ttsClient;
        this.aliTtsClient = aliTtsClient;
    }

    @Override
    public void run() {
        try {
            session.sendMessage(new TextMessage(replyAudioStart));
            logger.info("replyAudioStart");
            while (running) {
                sendSentenceAudio();
                sleep(100);
            }
            sendWholeRestSentence((ConcurrentLinkedQueue<String>) SessionManager.getPracticeCache(session).get(SENTENCE_CACHE));
            session.sendMessage(new TextMessage(replyAudioStop));
            if (ttsType.equals("STEP")) {
                //发送阶跃tts.text.done消息
                ttsClient.sendTextDone();
            }
            logger.info("replyAudioStop");
        } catch (IOException | InterruptedException e) {
            logger.error("send reply audio error", e);
        }
    }

    private void sendSentenceAudio() throws IOException {
        ConcurrentLinkedQueue<String> sentenceCache = (ConcurrentLinkedQueue<String>) SessionManager.getPracticeCache(session).get(SENTENCE_CACHE);
        while (!sentenceCache.isEmpty()) {
            if (sentWordCount < SENTENCE_SPLIT_LIMIT) {
                sendSplitSentence(sentenceCache);
            } else {
                sendWholeRestSentence(sentenceCache);
            }
        }
    }

    public void sendTextToTTS(String text) throws IOException {
        if (!interruptTTS) {
            logger.info("TTS 播放被打断，忽略音频数据发送");
            return;
        }

        logger.info("sendTextToTTS: {}", text);
        // 根据需要对文本进行分割，例如按句号分割
        String[] sentences = text.split("。");

        for (String sentence : sentences) {
            if (StringUtils.isNotEmpty(sentence.trim())) {
                sentence = filterBrackets(sentence.trim()); // 过滤括号
                if (ttsType.equals("STEP")) {
                    if (ttsClient == null || !ttsClient.isOpen()) {
                        reconnectTTSClient(); // 尝试重新连接 TTS 客户端
                    }
                    // 使用 Stepfun TTS 发送文本
                    ttsClient.sendAudioData(sentence);
                } else if (ttsType.equals("ALI")) {
                    //aliTtsClient.startSynthesis();
                    aliTtsClient.sendSynthesis(new String[]{sentence});
                    //aliTtsClient.stopSynthesis();
                } else {
                    // 使用原有 TTS 服务
                    byte[] responseBody = httpPost(sentence);
                    if (responseBody != null) {
                        byte[] audioData = parseTtsResponse(responseBody);
                        session.sendMessage(new BinaryMessage(audioData));
                        sentWordCount += sentence.length();
                        logger.info("sendSplitSentence sentence：{}， sentWordCount:{}， responseBody:{}",
                                sentence, sentWordCount, responseBody.length);
                    }
                }
            }
        }
    }

    public void sendFinalTextToTTS(String text) throws IOException {
        if (!interruptTTS) {
            logger.info("TTS 播放被打断，忽略音频数据发送");
            return;
        }

        logger.info("sendTextToTTS: {}", text);
        // 根据需要对文本进行分割，例如按句号分割

        if (ttsType.equals("STEP")) {
            if (ttsClient == null || !ttsClient.isOpen()) {
                reconnectTTSClient(); // 尝试重新连接 TTS 客户端
            }
            // 使用 Stepfun TTS 发送文本
            ttsClient.sendAudioData(text);
        }
    }


    private void reconnectTTSClient() {
        try {
            URI uri = new URI("wss://api.stepfun.com/v1/realtime/audio?model=step-tts-mini");
            this.ttsClient = new StepfunTTSClient(uri, session);
            this.ttsClient.connect(); // 尝试连接
            logger.info("重新创建并连接 Stepfun TTS 客户端成功");
        } catch (Exception e) {
            logger.error("重新创建 Stepfun TTS 客户端失败", e);
        }
    }

    private void sendWholeRestSentence(ConcurrentLinkedQueue<String> sentenceCache) throws IOException {
        if (!interruptTTS) {
            logger.info("TTS 播放被打断，忽略音频数据发送");
            return;
        }
        //logger.info("sendWholeRestSentence:{}", sentenceCache);
        StringBuilder wholeRestSentenceSb = new StringBuilder();
        while (!sentenceCache.isEmpty()) {
            String sentence = sentenceCache.poll();
            wholeRestSentenceSb.append(sentence);
        }
        if (!wholeRestSentenceSb.isEmpty()) {
            String content = wholeRestSentenceSb.toString();
            content = filterBrackets(content);
            if (ttsType.equals("STEP")) {
                // 使用 Stepfun TTS 发送文本
                ttsClient.sendAudioData(content);
            } else if (ttsType.equals("ALI")) {
                aliTtsClient.sendSynthesis(new String[]{content});
            } else {
                // 使用原有 TTS 服务
                byte[] responseBody = httpPost(content);
                if (responseBody != null) {
                    byte[] audioData = parseTtsResponse(responseBody);
                    session.sendMessage(new BinaryMessage(audioData));
                    sentWordCount += content.length();
                    //logger.info("sendWholeRestSentence 原始文本：{}， sentWordCount:{}， responseBody:{}", content, sentWordCount, responseBody.length);
                }
            }
        }
    }

    /**
     * 过滤掉括号及其内容
     *
     * @param input 原始字符串
     * @return 过滤后的字符串
     */
    private String filterBrackets(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        // 匹配中文括号和英文括号及其内容
        return input.replaceAll("（[^）]*）|\\([^)]*\\)", "");
    }

    private byte[] parseTtsResponse(byte[] responseBody) {
        try {
            String jsonStr = new String(responseBody, StandardCharsets.UTF_8);
            JsonObject jsonObject = JsonParser.parseString(jsonStr).getAsJsonObject();
            String base64Data = jsonObject.get("data").getAsString();
            return Base64.getDecoder().decode(base64Data);
        } catch (Exception e) {
            logger.error("解析 TTS 响应失败", e);
            return null;
        }
    }

    private void sendSplitSentence(ConcurrentLinkedQueue<String> sentenceCache) throws IOException {
        if (!interruptTTS) {
            logger.info("TTS 播放被打断，忽略音频数据发送");
            return;
        }
        logger.info("sendSplitSentence:{}", sentenceCache);
        String sentence = sentenceCache.poll();
        logger.info("sendSplitSentence sentence:" + sentence);
        if (StringUtils.isEmpty(sentence)) {
            logger.error("sentence is empty.");
            return;
        }
        sentence = filterBrackets(sentence);
        if (ttsType.equals("STEP")) {
            // 使用 Stepfun TTS 发送文本
            ttsClient.sendAudioData(sentence);
        } else if (ttsType.equals("ALI")) {
            aliTtsClient.sendSynthesis(new String[]{sentence});
        } else {
            // 使用原有 TTS 服务
            byte[] responseBody = httpPost(sentence);
            if (responseBody != null) {
                byte[] audioData = parseTtsResponse(responseBody);
                session.sendMessage(new BinaryMessage(audioData));
                sentWordCount += sentence.length();
                logger.info("sendSplitSentence sentence：{}， sentWordCount:{}， responseBody:{}",
                        sentence, sentWordCount, responseBody.length);
            }
        }
    }


    // 修改请求体构建方法
    private String buildTtsRequest(String text) {
        Map<String, Object> app = new HashMap<>();
        app.put("appid", TTS_APP_ID);
        app.put("token", TTS_TOKEN);
        app.put("cluster", TTS_CLUSTER);

        Map<String, Object> user = new HashMap<>();
        user.put("uid", DEFAULT_USER_UID);

        Map<String, Object> audio = new HashMap<>();
        audio.put("voice_type", VOICE_TYPE);
        audio.put("encoding", "wav");
        audio.put("speed_ratio", 1.0);
        audio.put("volume_ratio", 1.0);
        audio.put("pitch_ratio", 1.0);

        Map<String, Object> request = new HashMap<>();
        request.put("reqid", generateReqId());  // 生成唯一请求ID
        request.put("text", text);
        request.put("text_type", "plain");
        request.put("operation", "query");
        request.put("with_frontend", 1);
        request.put("frontend_type", "unitTson");

        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("app", app);
        requestBody.put("user", user);
        requestBody.put("audio", audio);
        requestBody.put("request", request);

        return GSON.toJson(requestBody);
    }

    // 生成唯一请求ID（示例实现）
    private String generateReqId() {
        return "REQ" + System.currentTimeMillis() + "_" +
                Thread.currentThread().getId();
    }


    // 修改HTTP请求方法
    private byte[] httpPost(String text) {
        try {
            String requestBody = buildTtsRequest(text);
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://openspeech.bytedance.com/api/v1/tts"))
                    .header("Content-Type", "application/json")
                    .header("Authorization", "Bearer;" + TTS_TOKEN)
                    .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                    .build();
            logger.info("TTS RequestBody:" + requestBody);
            HttpResponse<byte[]> response = client.send(request, BodyHandlers.ofByteArray());

            if (response.statusCode() == 200) {
                return response.body();
            } else {
                logger.error("TTS请求失败，状态码：{}，响应：{}",
                        response.statusCode(), new String(response.body()));
                return null;
            }
        } catch (IOException | InterruptedException e) {
            logger.error("TTS请求异常", e);
            return null;
        }
    }

    public void interruptTTS() {
        if (ttsType.equals("STEP") && ttsClient != null) {
            ttsClient.interrupt();
        }
    }

    public void setStop() {
        running = false;
    }
}